home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 2: Applications / Linux Cubed Series 2 - Applications.iso / circuits / pcb-1.000 / pcb-1 / pcb-1.3 / crosshair.c < prev    next >
C/C++ Source or Header  |  1995-02-27  |  17KB  |  541 lines

  1. /*
  2.  *                            COPYRIGHT
  3.  *
  4.  *  PCB, interactive printed circuit board design
  5.  *  Copyright (C) 1994,1995 Thomas Nau
  6.  *
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20.  *
  21.  *  Contact addresses for paper mail and Email:
  22.  *  Thomas Nau, Schlehenweg 15, 88471 Baustetten, Germany
  23.  *  Thomas.Nau@rz.uni-ulm.de
  24.  *
  25.  */
  26.  
  27. static    char    *rcsid = "$Header: /sda4/users/nau/src/pcb/RCS/crosshair.c,v 2.1 1994/09/28 14:26:07 nau Exp nau $";
  28.  
  29. /* crosshair stuff
  30.  */
  31.  
  32. #include <memory.h>
  33.  
  34. #include "global.h"
  35.  
  36. #include "crosshair.h"
  37. #include "data.h"
  38. #include "draw.h"
  39. #include "error.h"
  40. #include "mymem.h"
  41.  
  42. #include <X11/Xaw/Simple.h>
  43.  
  44. /* ---------------------------------------------------------------------------
  45.  * some local identifiers
  46.  */
  47. #define    SAVE_STACK_DEPTH    20            /* deep enough for what we use it for */
  48.  
  49. static    Boolean        CrosshairStack[SAVE_STACK_DEPTH];
  50. static    int            CrosshairStackPosition = 0;
  51. static    XPoint        *PolygonPoints = NULL;        /* data of tmp polygon */
  52. static    Cardinal    MaxPoints = 0;                /* number of points */
  53.  
  54. /* ---------------------------------------------------------------------------
  55.  * some local prototypes
  56.  */
  57. static    void    CreateTMPPolygon(PolygonTypePtr, Position, Position);
  58. static    void    DrawCrosshair(void);
  59. static    void    XORDrawElement(ElementTypePtr, Position, Position);
  60. static    void    XORDrawBuffer(BufferTypePtr);
  61. static    void    XORDrawMoveOrCopyObject(void);
  62. static    void    DrawAttached(Boolean);
  63. static    void    FitCrosshairIntoGrid(Position, Position);
  64.  
  65. /* ---------------------------------------------------------------------------
  66.  * creates a tmp polygon with coordinates converted to screen system
  67.  */
  68. static void CreateTMPPolygon(PolygonTypePtr Polygon, Position DX, Position DY)
  69. {
  70.         /* allocate memory for data with screen coordinates */
  71.     if (Polygon->PointN >= MaxPoints)
  72.     {
  73.             /* allocate memory for one additional point */
  74.         MaxPoints = Polygon->PointN +1;
  75.         PolygonPoints = (XPoint *) MyRealloc(PolygonPoints,
  76.             MaxPoints *sizeof(XPoint), "CreateTMPPolygon()");
  77.     }
  78.  
  79.         /* copy data to tmp array and convert it to screen coordinates */
  80.     POLYGONPOINT_LOOP(Polygon,
  81.         PolygonPoints[n].x = TO_SCREEN_X(point->X +DX);
  82.         PolygonPoints[n].y = TO_SCREEN_Y(point->Y +DY);
  83.     );
  84.  
  85.         /* the last point is identical to the first one */
  86.     PolygonPoints[Polygon->PointN].x = PolygonPoints[0].x;
  87.     PolygonPoints[Polygon->PointN].y = PolygonPoints[0].y;
  88. }
  89.  
  90. /* ---------------------------------------------------------------------------
  91.  * draws the crosshair 
  92.  * don't transform MAX_COORD to screen coordinats, it is
  93.  * already the maximum of screen- and pcb-coordinates
  94.  */
  95. static void DrawCrosshair(void)
  96. {
  97.     XDrawLine(Dpy, Output.OutputWindow, Crosshair.GC,
  98.         TO_SCREEN_X(Crosshair.X), 0, TO_SCREEN_X(Crosshair.X), MAX_COORD);
  99.     XDrawLine(Dpy, Output.OutputWindow, Crosshair.GC,
  100.         0, TO_SCREEN_Y(Crosshair.Y), MAX_COORD, TO_SCREEN_Y(Crosshair.Y));
  101. }
  102.  
  103. /* ---------------------------------------------------------------------------
  104.  * draws the elements of a loaded circuit which is to be merged in
  105.  */
  106. static void XORDrawElement(ElementTypePtr Element, Position DX, Position DY)
  107. {
  108.     ELEMENTLINE_LOOP(Element,
  109.         XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  110.             TO_SCREEN_X(DX +line->X1), TO_SCREEN_Y(DY +line->Y1),
  111.             TO_SCREEN_X(DX +line->X2), TO_SCREEN_Y(DY +line->Y2));
  112.     );
  113.  
  114.         /* arc coordinates and angles have to be converted to X11 notation */
  115.     ARC_LOOP(Element,
  116.         XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  117.             TO_SCREEN_X(DX +arc->X -arc->Width),
  118.             TO_SCREEN_Y(DY +arc->Y -arc->Height),
  119.             TO_SCREEN(2*arc->Width), TO_SCREEN(2*arc->Height),
  120.             (arc->StartAngle +180) *64, arc->Delta *64);
  121.     );
  122.  
  123.         /* pin coordinates and angles have to be converted to X11 notation */
  124.     PIN_LOOP(Element,
  125.         XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  126.             TO_SCREEN_X(DX +pin->X -pin->Thickness/2),
  127.             TO_SCREEN_Y(DY +pin->Y -pin->Thickness/2),
  128.             TO_SCREEN(pin->Thickness), TO_SCREEN(pin->Thickness),
  129.             0, 360*64);
  130.     );
  131. }
  132.  
  133. /* ---------------------------------------------------------------------------
  134.  * draws all visible and attached objects of the pastebuffer
  135.  */
  136. static void XORDrawBuffer(BufferTypePtr Buffer)
  137. {
  138.     Cardinal    i;
  139.     Position    x, y;
  140.  
  141.         /* set offset */
  142.     x = Crosshair.X -Buffer->X;
  143.     y = Crosshair.Y -Buffer->Y;
  144.  
  145.         /* draw all visible layers */
  146.     for (i = 0; i < MAX_LAYER; i++)
  147.         if (PCB->Data->Layer[i].On)
  148.         {
  149.             LayerTypePtr    layer = &Buffer->Data->Layer[i];
  150.  
  151.             LINE_LOOP(layer,
  152.                 XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  153.                     TO_SCREEN_X(x +line->X1), TO_SCREEN_Y(y +line->Y1),
  154.                     TO_SCREEN_X(x +line->X2), TO_SCREEN_Y(y +line->Y2));
  155.             );
  156.             TEXT_LOOP(layer,
  157.                 {
  158.                     BoxTypePtr    box = &text->BoundingBox;
  159.  
  160.                     XDrawRectangle(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  161.                         TO_SCREEN_X(x +box->X1), TO_SCREEN_Y(y +box->Y1),
  162.                         TO_SCREEN(box->X2 -box->X1),
  163.                         TO_SCREEN(box->Y2 -box->Y1));
  164.                 }
  165.             );
  166.                 /* the tmp polygon has n+1 points because the first
  167.                  * and the last one are set to the same coordinates
  168.                  */
  169.             POLYGON_LOOP(layer,
  170.                 {
  171.                     CreateTMPPolygon(polygon, x, y);
  172.                     XDrawLines(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  173.                         PolygonPoints, polygon->PointN+1, CoordModeOrigin);
  174.                 }
  175.             );
  176.         }
  177.  
  178.         /* draw elements if visible */
  179.     if (PCB->PinOn || PCB->ElementOn)
  180.         ELEMENT_LOOP(Buffer->Data, XORDrawElement(element, x, y););
  181.  
  182.         /* and the vias, move offset by thickness/2 */
  183.     if (PCB->ViaOn)
  184.         VIA_LOOP(Buffer->Data,
  185.             XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  186.                 TO_SCREEN_X(x +via->X -via->Thickness/2),
  187.                 TO_SCREEN_Y(y +via->Y -via->Thickness/2),
  188.                 TO_SCREEN(via->Thickness), TO_SCREEN(via->Thickness),
  189.                 0, 360*64);
  190.         );
  191. }
  192.  
  193. /* ---------------------------------------------------------------------------
  194.  * draws the attched object while in MOVE_MODE or COPY_MODE
  195.  */
  196. static void XORDrawMoveOrCopyObject(void)
  197. {
  198.     Position    dx = Crosshair.X -Crosshair.AttachedObject.X,
  199.                 dy = Crosshair.Y -Crosshair.AttachedObject.Y;
  200.  
  201.     switch(Crosshair.AttachedObject.Type)
  202.     {
  203.         case VIA_TYPE:
  204.         {
  205.             PinTypePtr    via = (PinTypePtr) Crosshair.AttachedObject.Ptr2;
  206.  
  207.             XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  208.                 TO_SCREEN_X(Crosshair.X -via->Thickness/2),
  209.                 TO_SCREEN_Y(Crosshair.Y -via->Thickness/2),
  210.                 TO_SCREEN(via->Thickness), TO_SCREEN(via->Thickness),0,360*64);
  211.             break;
  212.         }
  213.  
  214.         case LINE_TYPE:
  215.         {
  216.             LineTypePtr    line = (LineTypePtr) Crosshair.AttachedObject.Ptr2;
  217.  
  218.             XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  219.                 TO_SCREEN_X(line->X1 +dx), TO_SCREEN_Y(line->Y1 +dy),
  220.                 TO_SCREEN_X(line->X2 +dx), TO_SCREEN_Y(line->Y2 +dy));
  221.             break;
  222.         }
  223.  
  224.         case POLYGON_TYPE:
  225.         {
  226.             PolygonTypePtr    polygon = (PolygonTypePtr) Crosshair.AttachedObject.Ptr2;
  227.  
  228.                 /* the tmp polygon has n+1 points because the first
  229.                  * and the last one are set to the same coordinates
  230.                  */
  231.             CreateTMPPolygon(polygon, dx, dy);
  232.             XDrawLines(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  233.                 PolygonPoints, polygon->PointN +1, CoordModeOrigin);
  234.             break;
  235.         }
  236.  
  237.         case POLYGONPOINT_TYPE:
  238.         {
  239.             PolygonTypePtr        polygon;
  240.             PolygonPointTypePtr    point,
  241.                                 previous,
  242.                                 following;
  243.  
  244.             polygon = (PolygonTypePtr) Crosshair.AttachedObject.Ptr1;
  245.             point = (PolygonPointTypePtr) Crosshair.AttachedObject.Ptr2;
  246.  
  247.                 /* get previous and following point */
  248.             if (point == polygon->Points)
  249.             {
  250.                 previous = &polygon->Points[polygon->PointN-1];
  251.                 following = point+1;
  252.             }
  253.             else
  254.                 if (point == &polygon->Points[polygon->PointN-1])
  255.                 {
  256.                     previous = point-1;
  257.                     following = &polygon->Points[0];
  258.                 }
  259.                 else
  260.                 {
  261.                     previous = point-1;
  262.                     following = point+1;
  263.                 }
  264.  
  265.                 /* draw the two segments */
  266.             XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  267.                 TO_SCREEN_X(previous->X), TO_SCREEN_Y(previous->Y),
  268.                 TO_SCREEN_X(point->X +dx), TO_SCREEN_Y(point->Y +dy));
  269.             XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  270.                 TO_SCREEN_X(point->X +dx), TO_SCREEN_Y(point->Y +dy),
  271.                 TO_SCREEN_X(following->X), TO_SCREEN_Y(following->Y));
  272.             break;
  273.         }
  274.  
  275.             /* element names are moved like normal text objects */
  276.         case TEXT_TYPE:
  277.         case ELEMENTNAME_TYPE:
  278.         {
  279.             BoxTypePtr    box;
  280.  
  281.             box = &((TextTypePtr) Crosshair.AttachedObject.Ptr2)->BoundingBox;
  282.             XDrawRectangle(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  283.                 TO_SCREEN_X(box->X1 +dx), TO_SCREEN_Y(box->Y1 +dy),
  284.                 TO_SCREEN(box->X2 -box->X1), TO_SCREEN(box->Y2 -box->Y1));
  285.             break;
  286.         }
  287.  
  288.             /* pin movements result in moving an element */
  289.         case PIN_TYPE:
  290.         case ELEMENT_TYPE:
  291.             XORDrawElement((ElementTypePtr) Crosshair.AttachedObject.Ptr2,
  292.                 dx, dy);
  293.             break;
  294.     }
  295. }
  296.  
  297. /* ---------------------------------------------------------------------------
  298.  * draws additional stuff that follows the crosshair
  299.  */
  300. static void DrawAttached(Boolean BlockToo)
  301. {
  302.     DrawCrosshair();
  303.     switch (Settings.Mode)
  304.     {
  305.         case VIA_MODE:
  306.             XDrawArc(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  307.                 TO_SCREEN_X(Crosshair.X -Settings.ViaThickness/2),
  308.                 TO_SCREEN_Y(Crosshair.Y -Settings.ViaThickness/2),
  309.                 TO_SCREEN(Settings.ViaThickness),
  310.                 TO_SCREEN(Settings.ViaThickness),
  311.                 0, 360*64);
  312.             break;
  313.             
  314.             /* the attached line is used by both LINEMODE and POLYGON_MODE */
  315.         case LINE_MODE:
  316.         case POLYGON_MODE:
  317.                 /* draw only if starting point is set */
  318.             if (Crosshair.AttachedLine.State != STATE_FIRST)
  319.                 XDrawLine(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  320.                     TO_SCREEN_X(Crosshair.AttachedLine.X1),
  321.                     TO_SCREEN_Y(Crosshair.AttachedLine.Y1),
  322.                     TO_SCREEN_X(Crosshair.AttachedLine.X2),
  323.                     TO_SCREEN_Y(Crosshair.AttachedLine.Y2));
  324.  
  325.                 /* draw attached polygon only if in POLYGON_MODE */
  326.             if (Settings.Mode == POLYGON_MODE &&
  327.                 Crosshair.AttachedPolygon.PointN > 1)
  328.             {
  329.                 CreateTMPPolygon(&Crosshair.AttachedPolygon, 0, 0);
  330.                 XDrawLines(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  331.                     PolygonPoints, Crosshair.AttachedPolygon.PointN,
  332.                     CoordModeOrigin);
  333.             }
  334.             break;
  335.  
  336.         case PASTEBUFFER_MODE:
  337.             XORDrawBuffer(PASTEBUFFER);
  338.             break;
  339.  
  340.         case COPY_MODE:
  341.         case MOVE_MODE:
  342.             XORDrawMoveOrCopyObject();
  343.             break;
  344.     }
  345.  
  346.         /* an attached box does not depend on a special mode */
  347.     if (Crosshair.AttachedBox.State == STATE_SECOND ||
  348.         (BlockToo && Crosshair.AttachedBox.State == STATE_THIRD))
  349.     {
  350.         Position    x1, y1,     /* upper left corner */
  351.                     x2, y2;     /* lower right corner */
  352.  
  353.         x1 = MIN(Crosshair.AttachedBox.X1, Crosshair.AttachedBox.X2);
  354.         y1 = MIN(Crosshair.AttachedBox.Y1, Crosshair.AttachedBox.Y2);
  355.         x2 = MAX(Crosshair.AttachedBox.X1, Crosshair.AttachedBox.X2);
  356.         y2 = MAX(Crosshair.AttachedBox.Y1, Crosshair.AttachedBox.Y2);
  357.         XDrawRectangle(Dpy, Output.OutputWindow, Crosshair.AttachGC,
  358.             TO_SCREEN_X(x1), TO_SCREEN_Y(y1),
  359.             TO_SCREEN(x2-x1), TO_SCREEN(y2-y1));
  360.     }
  361. }
  362.  
  363. /* ---------------------------------------------------------------------------
  364.  * switches crosshair on
  365.  */
  366. void CrosshairOn(Boolean BlockToo)
  367. {
  368.     if (!Crosshair.On)
  369.     {
  370.         Crosshair.On = True;
  371.         DrawAttached(BlockToo);
  372.     }
  373. }
  374.  
  375. /* ---------------------------------------------------------------------------
  376.  * switches crosshair off
  377.  */
  378. void CrosshairOff(Boolean BlockToo)
  379. {
  380.     if (Crosshair.On)
  381.     {
  382.         Crosshair.On = False;
  383.         DrawAttached(BlockToo);
  384.     }
  385. }
  386.  
  387. /* ---------------------------------------------------------------------------
  388.  * saves crosshair state (on/off) and hides him
  389.  */
  390. void HideCrosshair(Boolean BlockToo)
  391. {
  392.     CrosshairStack[CrosshairStackPosition++] = Crosshair.On;
  393.     if (CrosshairStackPosition >= SAVE_STACK_DEPTH)
  394.         CrosshairStackPosition--;
  395.     CrosshairOff(BlockToo);
  396. }
  397.  
  398. /* ---------------------------------------------------------------------------
  399.  * restores last crosshair state
  400.  */
  401. void RestoreCrosshair(Boolean BlockToo)
  402. {
  403.     if (CrosshairStackPosition)
  404.     {
  405.         if (CrosshairStack[--CrosshairStackPosition])
  406.             CrosshairOn(BlockToo);
  407.         else
  408.             CrosshairOff(BlockToo);
  409.     }
  410. }
  411.  
  412. /* ---------------------------------------------------------------------------
  413.  * recalculates the passed coordinates to fit the current grid setting
  414.  */
  415. static void FitCrosshairIntoGrid(Position X, Position Y)
  416. {
  417.     Position    x1, y1, x2, y2;
  418.     
  419.         /* get PCB coordinates from visible display size */
  420.     x1 = TO_PCB_X(Output.OffsetX);
  421.     y1 = TO_PCB_Y(Output.OffsetY);
  422.     x2 = TO_PCB_X(Output.OffsetX +Output.Width -1);
  423.     y2 = TO_PCB_Y(Output.OffsetY +Output.Height -1);
  424.  
  425.         /* check position agains window size and agains valid
  426.          * coordinates determined by the size of an attached
  427.          * object or buffer
  428.          */
  429.     Crosshair.X = (X < x1 || X > x2) ? Crosshair.X : X;
  430.     Crosshair.Y = (Y < y1 || Y > y2) ? Crosshair.Y : Y;
  431.     Crosshair.X = MIN(Crosshair.MaxX, MAX(Crosshair.MinX, Crosshair.X));
  432.     Crosshair.Y = MIN(Crosshair.MaxY, MAX(Crosshair.MinY, Crosshair.Y));
  433.     
  434.         /* check if new position is inside the output window
  435.          * This might not be true after the window has been resized.
  436.          * In this case we just set it to the center of the window or
  437.          * with respect to the grid (if possible)
  438.          */
  439.     if (Crosshair.X < x1 || Crosshair.X > x2)
  440.     {
  441.         if (x2 -x1 +1 >= PCB->Grid)
  442.                 /* there must be a point that matches the grid 
  443.                  * so we just have to look for it with some integer
  444.                  * calculations
  445.                  */
  446.             Crosshair.X = GRIDFIT_X(x1 +PCB->Grid);
  447.         else
  448.             Crosshair.X = (x1+x2)/2;
  449.     }
  450.     else
  451.             /* check if the new position matches the grid */
  452.         Crosshair.X = GRIDFIT_X(Crosshair.X);
  453.  
  454.         /* to the same for the second coordinate */
  455.     if (Crosshair.Y < y1 || Crosshair.Y > y2)
  456.     {
  457.         if (y2 -y1 +1 >= PCB->Grid)
  458.             Crosshair.Y = GRIDFIT_Y(y1 +PCB->Grid);
  459.         else
  460.             Crosshair.Y = (y1+y2)/2;
  461.     }
  462.     else
  463.         Crosshair.Y = GRIDFIT_Y(Crosshair.Y);
  464. }
  465.  
  466. /* ---------------------------------------------------------------------------
  467.  * move crosshair relative (has to be switched off)
  468.  */
  469. void MoveCrosshairRelative(Position DeltaX, Position DeltaY)
  470. {
  471.     FitCrosshairIntoGrid(Crosshair.X +DeltaX, Crosshair.Y +DeltaY);
  472. }
  473.  
  474. /* ---------------------------------------------------------------------------
  475.  * move crosshair absolute (has to be switched off)
  476.  */
  477. void MoveCrosshairAbsolute(Position X, Position Y)
  478. {
  479.     FitCrosshairIntoGrid(X, Y);
  480. }
  481.  
  482. /* ---------------------------------------------------------------------------
  483.  * sets the valid range for the crosshair cursor
  484.  */
  485. void SetCrosshairRange(Position MinX, Position MinY,
  486.     Position MaxX, Position MaxY)
  487. {
  488.     Crosshair.MinX = MAX(0, MinX);
  489.     Crosshair.MinY = MAX(0, MinY);
  490.     Crosshair.MaxX = MIN((Position) PCB->MaxWidth, MaxX);
  491.     Crosshair.MaxY = MIN((Position) PCB->MaxHeight, MaxY);
  492.  
  493.         /* force update of position */
  494.     MoveCrosshairRelative(0, 0);
  495. }
  496.  
  497. /* ---------------------------------------------------------------------------
  498.  * initializes crosshair stuff
  499.  * clears the struct, allocates to graphical contexts and
  500.  * initializes the stack
  501.  */
  502. void InitCrosshair(void)
  503. {
  504.         /* clear struct */
  505.     memset(&Crosshair, 0, sizeof(CrosshairType));
  506.  
  507.     Crosshair.GC = XCreateGC(Dpy, Output.OutputWindow, 0, NULL);
  508.     Crosshair.AttachGC = XCreateGC(Dpy, Output.OutputWindow, 0, NULL);
  509.     if (!VALID_GC((int) Crosshair.GC) || !VALID_GC((int) Crosshair.AttachGC))
  510.         MyFatal("can't create default crosshair GC\n");
  511.     XSetState(Dpy, Crosshair.GC, Settings.CrosshairColor, Settings.bgColor,
  512.         GXxor, AllPlanes);
  513.  
  514.         /* change to invert mode for drawing buffer contents */
  515.     XCopyGC(Dpy, Crosshair.GC, -1, Crosshair.AttachGC);
  516.     XSetState(Dpy, Crosshair.AttachGC, Settings.bgColor,
  517.         Settings.CrosshairColor, GXinvert, AllPlanes);
  518.  
  519.         /* fake an crosshair off entry on stack */
  520.     CrosshairStackPosition = 0;
  521.     CrosshairStack[CrosshairStackPosition++] = True;
  522.     Crosshair.On = False;
  523.  
  524.         /* set default limits */
  525.     Crosshair.MinX = Crosshair.MinY = 0;
  526.     Crosshair.MaxX = PCB->MaxWidth;
  527.     Crosshair.MaxY = PCB->MaxHeight;
  528. }
  529.  
  530. /* ---------------------------------------------------------------------------
  531.  * exits crosshair routines, release GCs
  532.  */
  533. void DestroyCrosshair(void)
  534. {
  535.     CrosshairOff(True);
  536.     FreePolygonMemory(&Crosshair.AttachedPolygon);
  537.     XFreeGC(Dpy, Crosshair.GC);
  538.     XFreeGC(Dpy, Crosshair.AttachGC);
  539. }
  540.  
  541.